package fi.foyt.cs.api.events;

import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Logger;

import javax.mail.MessagingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;

import fi.foyt.cs.Settings;
import fi.foyt.cs.controller.SystemController;
import fi.foyt.cs.controller.UserController;
import fi.foyt.cs.locale.Messages;
import fi.foyt.cs.mail.MailUtils;
import fi.foyt.cs.persistence.domainmodel.system.ExternalLinkVerificationCode;
import fi.foyt.cs.persistence.domainmodel.user.User;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class FriendEventsExecutorServlet extends HttpServlet {

  private static final long serialVersionUID = 2856012243985434546L;

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    long started = System.currentTimeMillis();

    response.setContentType("text/plain");
   
    FriendEvent friendEvent = FriendEvent.valueOf(request.getParameter("event"));
    Long userId = NumberUtils.createLong(request.getParameter("userId"));
    Long friendId = NumberUtils.createLong(request.getParameter("friendId"));

    logger.info("Executing friend event: " + friendEvent);

    UserController userController = new UserController();

    User user = userController.findUserById(userId);
    User friend = userController.findUserById(friendId);

    try {
      switch (friendEvent) {
        case FriendAdded:
          handleFriendAdded(user, friend);
        break;
        case FriendRemoved:
          handleFriendRemoved(user, friend);
        break;
        case FriendshipAccepted:
          handleFriendshipAccepted(user, friend);
        break;
        case FriendshipRejected:
          handleFriendshipRejected(user, friend);
        break;
      }
  
      response.getWriter().write("OK");
    } catch (Exception e) {
      response.getWriter().write("Error occured: " + e.getMessage());
    }

    logger.info("Finished executing event: " + friendEvent + ". Execution time was " + (System.currentTimeMillis() - started) + "ms");
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doGet(request, response);
  }

  private void handleFriendAdded(User user, User friend) throws UnsupportedEncodingException, MessagingException, IOException, TemplateException {
    SystemController systemController = new SystemController();

    Map<String, Object> data = new HashMap<String, Object>();

    String userName = user.getFirstName() + " " + user.getLastName();
    String friendName = friend.getFirstName() + " " + friend.getLastName();
    Locale locale = StringUtils.isBlank(friend.getLocale()) ? Settings.getDefaultLocale() : new Locale(friend.getLocale());
    String subject = Messages.getInstance().getText(locale, "generic.events.friends.friendAddedSubject", userName);
    String extra = "friendId=" + String.valueOf(user.getId().getId());
    
    String verificationCode = Thread.currentThread().getName() + "-" + Long.toHexString(System.currentTimeMillis());
    ExternalLinkVerificationCode externalLinkVerificationCode = systemController.createExternalLinkVerificationCode(friend, verificationCode, extra);

    data.put("toUser", user);
    data.put("fromUser", friend);
    data.put("rejectLink", Settings.getServerUrl("/actions/friends/reject?elvc=" + externalLinkVerificationCode.getVerificationCode() + "&u=" + friend.getId().getId()));
    data.put("acceptLink", Settings.getServerUrl("/actions/friends/accept?elvc=" + externalLinkVerificationCode.getVerificationCode() + "&u=" + friend.getId().getId()));

    MailUtils.sendMail(subject, getMailTemplate("/friends/friendAdded.ftl", data, locale), "text/html", user.getEmail(), userName, friend.getEmail(), friendName);
  }

  private void handleFriendRemoved(User user, User friend) throws UnsupportedEncodingException, MessagingException, IOException, TemplateException {
    Map<String, Object> data = new HashMap<String, Object>();

    String userName = user.getFirstName() + " " + user.getLastName();
    String friendName = friend.getFirstName() + " " + friend.getLastName();
    Locale locale = StringUtils.isBlank(friend.getLocale()) ? Settings.getDefaultLocale() : new Locale(friend.getLocale());
    String subject = Messages.getInstance().getText(locale, "generic.events.friends.friendRemovedSubject", userName);

    data.put("toUser", user);
    data.put("fromUser", friend);

    MailUtils.sendMail(subject, getMailTemplate("/friends/friendRemoved.ftl", data, locale), "text/html", user.getEmail(), userName, friend.getEmail(), friendName);
  }

  private void handleFriendshipAccepted(User user, User friend) throws UnsupportedEncodingException, MessagingException, IOException, TemplateException {
    Map<String, Object> data = new HashMap<String, Object>();

    String userName = user.getFirstName() + " " + user.getLastName();
    String friendName = friend.getFirstName() + " " + friend.getLastName();
    Locale locale = StringUtils.isBlank(friend.getLocale()) ? Settings.getDefaultLocale() : new Locale(friend.getLocale());
    String subject = Messages.getInstance().getText(locale, "generic.events.friends.friendshipAcceptedSubject", userName);

    data.put("toUser", user);
    data.put("fromUser", friend);

    MailUtils.sendMail(subject, getMailTemplate("/friends/friendshipAccepted.ftl", data, locale), "text/html", user.getEmail(), userName, friend.getEmail(), friendName);
  }

  private void handleFriendshipRejected(User user, User friend) throws UnsupportedEncodingException, MessagingException, IOException, TemplateException {
    Map<String, Object> data = new HashMap<String, Object>();

    String userName = user.getFirstName() + " " + user.getLastName();
    String friendName = friend.getFirstName() + " " + friend.getLastName();
    Locale locale = StringUtils.isBlank(friend.getLocale()) ? Settings.getDefaultLocale() : new Locale(friend.getLocale());
    String subject = Messages.getInstance().getText(locale, "generic.events.friends.friendshipRejectedSubject", userName);

    data.put("toUser", user);
    data.put("fromUser", friend);

    MailUtils.sendMail(subject, getMailTemplate("/friends/friendshipRejected.ftl", data, locale), "text/html", user.getEmail(), userName, friend.getEmail(), friendName);
  }

  private String getMailTemplate(String templateName, Map<String, Object> model, Locale locale) throws IOException, TemplateException {
    Configuration config = new Configuration(); // class:/
    TemplateLoader templateLoader = new ClassTemplateLoader(getClass(), "/fi/foyt/cs/api/events/templates");
    config.setTemplateLoader(templateLoader);
    config.setLocale(locale);
    Template template = config.getTemplate(templateName);
    StringWriter result = new StringWriter();
    template.process(model, result);
    return result.toString();
  }

  private Logger logger = Logger.getLogger(FriendEventsExecutorServlet.class.getName());
}
